package com.fdb.efp.nls.service.impl.common;

import com.fdb.efp.nls.service.facade.NlsApplyInfoService;
import com.fdb.efp.nls.service.facade.UpdateLmtPrdContService;
import com.fdb.efp.nls.service.vo.NlsApplyInfoVO;
import com.fdb.basic.framework.core.exception.BizException;
//import com.fdb.basic.framework.redis.curator.CuratorLock;
import com.fdb.basic.framework.redis.lock.RedisLock;
import com.fdb.efp.limit.service.facade.LmtPrdContService;
import com.fdb.efp.limit.service.vo.LmtPrdContVO;
import com.fdb.efp.nls.service.facade.AccLoanService;
import com.fdb.efp.nls.service.facade.LoanRepayDetailService;
import com.fdb.efp.nls.service.vo.AccLoanVO;
import com.fdb.efp.loan.service.vo.LoanRepayDetailVO;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.fdb.basic.framework.core.constant.BaseConstant.*;

/**
 * 需求编号：【2019D0519】（业务提的需求编号）
 * 问题编号：【xxxxxxx】（若不是因为修复问题而新增该类，则留空）
 * 开发人员：caoxin
 * 创建日期：2019年7月8日 下午7:53:31
 * 功能描述：授信协议额度信息操作实现
 */
@Service("updateLmtPrdContService")
public class UpdateLmtPrdContServiceImpl implements UpdateLmtPrdContService {

	private static Logger logger = LoggerFactory.getLogger(UpdateLmtPrdContServiceImpl.class);

	private static final String LMT_PRO_LOCK = "/wd/psd/lmt_prod/";

	private static final long DEFAULT_EXPIRE_TIME = 3 * 60;

	@Autowired
	@Qualifier("nlsApplyInfoService")
	private NlsApplyInfoService nlsApplyInfoService;

	@Autowired
	@Qualifier("accLoanService")
	private AccLoanService accLoanService;

	@Autowired
	@Qualifier("loanRepayDetailService")
	private LoanRepayDetailService loanRepayDetailService;

	@Autowired
	@Qualifier("lmtPrdContService")
	private LmtPrdContService lmtPrdContService;

//	@Autowired
//	private CuratorLock curatorLock;


	@Override
	public BigDecimal getPreOccAmt(String lmtApplySeq) {
		logger.info("通过授信申请流水号【" + lmtApplySeq + "】,获取所有在途的用信申请信息开始------------------- 目前表示在途的状态有【处理中、挂起】");
		NlsApplyInfoVO nlsApplyInfoVo = new NlsApplyInfoVO();
		nlsApplyInfoVo.setLmtApplySeq(lmtApplySeq);
		nlsApplyInfoVo.setNlsApplyState(NLS_APPLY_STATE_01);
		List<NlsApplyInfoVO> nlsApplyInfoVs = Optional.ofNullable(nlsApplyInfoService.queryListByLmtApplySqe(nlsApplyInfoVo)).orElseGet(ArrayList::new);
		// 计算预占用额度
		return nlsApplyInfoVs.
				stream().
				map(NlsApplyInfoVO::getApplyAmt).
				filter(Objects::nonNull).
				reduce(BigDecimal.ZERO, BigDecimal::add);
	}

	@Override
	public List<String> getApplySeqList(String lmtApplySeq) {
		logger.info("通过授信申请流水号【" + lmtApplySeq + "】,获取所有用信申请信息开始-------------------");
		List<NlsApplyInfoVO> nlsApplyInfoVOS = nlsApplyInfoService.queryAllByLmtApplySeq(lmtApplySeq);
		List<String> applySeqs = nlsApplyInfoVOS.
				stream().
				map(NlsApplyInfoVO::getApplySeq).
				filter(StringUtils::isNotEmpty).
				collect(Collectors.toList());
		logger.info("通过授信申请流水号【" + lmtApplySeq + "】,获取所有用信申请信息结束--------结果集数为：" + applySeqs.size());
		return applySeqs;
	}

	@Override
	public BigDecimal getOccAmt(List<String> applySeqs) {
		// 第一次支用申请时，已用额度为零
		if (null == applySeqs || applySeqs.isEmpty()) {
			return BigDecimal.ZERO;
		}
		// 通过用信申请流水号统计所有借据的借据余额
		List<AccLoanVO> accLoanVOS = Optional.ofNullable(accLoanService.queryByApplySqes(applySeqs)).orElseGet(ArrayList::new);
		return accLoanVOS.
				stream().
				map(AccLoanVO::getLoanBalance).
				filter(Objects::nonNull).
				reduce(BigDecimal.ZERO, BigDecimal::add);
	}

	@Override
	@RedisLock(keyParamNames = {"lmtApplySeq"})
	public void  updateLmtProdAfterLoanRelease(String lmtApplySeq, String applySeq) {
		try{
			LmtPrdContVO lmtPrdContVO = new LmtPrdContVO();
			lmtPrdContVO.setLmtApplySeq(lmtApplySeq);
			lmtPrdContVO = lmtPrdContService.queryByPk(lmtPrdContVO);
			if (Objects.nonNull(lmtPrdContVO)) {
				// 在途的为当前的预占用额度,因为这里只有一笔
				BigDecimal preOCcAmt = lmtPrdContVO.getPreOccAmt();
				// 获取已用额度,所有成功的用信申请信息的贷款余额向加
				List<String> successApplySeq = getSuccessApplySeq(lmtApplySeq);
				BigDecimal occAmt = getOccAmt(successApplySeq);
				takeUpLmt(lmtPrdContVO, occAmt,preOCcAmt);
				apprSuccess(applySeq);
			}
		}catch (Exception e){
			e.printStackTrace();
		}

	}

	@Override
    @RedisLock(keyParamNames = {"lmtApplySeq"})
    public void updateLmtProdAfterRepay(String lmtApplySeq, String applySeq,String setlSeq) {
		try {
			LmtPrdContVO lmtPrdContVO = new LmtPrdContVO();
			lmtPrdContVO.setLmtApplySeq(lmtApplySeq);
			lmtPrdContVO = lmtPrdContService.queryByPk(lmtPrdContVO);
			if (Objects.nonNull(lmtPrdContVO)) {
				BigDecimal occAmt = getOccAmt(getSuccessApplySeq(lmtApplySeq));
				BigDecimal preOccAmt = getPreOccAmt(lmtApplySeq);
				normalTakeUpLmt(occAmt, preOccAmt, lmtPrdContVO);

				LoanRepayDetailVO loanRepayDetailVO = new LoanRepayDetailVO();
				loanRepayDetailVO.setSetlSeq(setlSeq);
				loanRepayDetailVO = loanRepayDetailService.queryByPk(loanRepayDetailVO);
				if (Objects.nonNull(loanRepayDetailVO)) {
					loanRepayDetailVO.setWfApprSts(NLS_APPLY_STATE_02);
					loanRepayDetailVO.setRpSts(RY_STS_1);
					try {
						int result = loanRepayDetailService.updateByPk(loanRepayDetailVO);
						if (result != 1) {
							logger.error("还款明细表【" + loanRepayDetailVO.getSetlSeq() + "】 同步成功后更新还款明细状态为失败");
							throw new BizException("还款明细表【" + loanRepayDetailVO.getSetlSeq() + "】同步成功后更新还款明细状态为失败");
						}
					} catch (Exception e) {
						e.printStackTrace();
						logger.error("还款明细表【" + loanRepayDetailVO.getSetlSeq() + "】同步成功后更新还款明细状态为失败");
						throw new BizException("还款明细表【" + loanRepayDetailVO.getSetlSeq() + "】同步成功后更新还款明细状态为失败");
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void apprSuccess(String applySeq) throws BizException {
		NlsApplyInfoVO nlsApplyInfoVO = new NlsApplyInfoVO();
		nlsApplyInfoVO.setApplySeq(applySeq);
		nlsApplyInfoVO = nlsApplyInfoService.queryByPk(nlsApplyInfoVO);
		if (Objects.nonNull(nlsApplyInfoVO)) {
			nlsApplyInfoVO.setNlsApplyState(NLS_APPLY_STATE_02);
			nlsApplyInfoVO.setExecuteTime(6);
			try {
				int result = nlsApplyInfoService.updateByPk(nlsApplyInfoVO);
				if (result != 1) {
					logger.error("授信协议表 授信申请流水号【" + nlsApplyInfoVO.getLmtApplySeq() + "】用信申请流水号【" + applySeq + "】同步成功后更新用信状态为失败");
					throw new BizException("授信协议表 授信申请流水号【" + nlsApplyInfoVO.getLmtApplySeq() + "】用信申请流水号【" + applySeq + "】同步成功后更新用信状态为失败");
				}
			} catch (Exception e) {
				logger.error("授信协议表 授信申请流水号【" + nlsApplyInfoVO.getLmtApplySeq() + "】用信申请流水号【" + applySeq + "】同步成功后更新用信状态为失败");
				e.printStackTrace();
				throw new BizException("授信协议表 授信申请流水号【" + nlsApplyInfoVO.getLmtApplySeq() + "】用信申请流水号【" + applySeq + "】同步成功后更新用信状态为失败");
			}
		}
	}

	private void takeUpLmt(LmtPrdContVO lmtPrdContVO, BigDecimal occAmt, BigDecimal preOccAmt) throws BizException {
		BigDecimal newOccAmt = occAmt.add(preOccAmt);
		lmtPrdContVO.setOccAmt(newOccAmt);
		lmtPrdContVO.setPreOccAmt(BigDecimal.ZERO);
		lmtPrdContVO.setAvailAmt(lmtPrdContVO.getLmtAmt().subtract(newOccAmt));
		int result = lmtPrdContService.updateByPk(lmtPrdContVO);
		if (result != 1) {
			logger.error("授信协议表 授信申请流水号【" + lmtPrdContVO.getLmtApplySeq() + "】额度占用是失败");
			throw new BizException("授信协议表 授信申请流水号【" + lmtPrdContVO.getLmtApplySeq() + "】额度占用是失败");
		}
	}

	@Override
    @RedisLock(keyParamNames = {"lmtApplySeq"})
    public void updateLmtPro(String lmtApplySeq,String applySeq) {
        try{
            LmtPrdContVO lmtPrdContVO = new LmtPrdContVO();
            lmtPrdContVO.setLmtApplySeq(lmtApplySeq);
            lmtPrdContVO = lmtPrdContService.queryByPk(lmtPrdContVO);
            if (Objects.nonNull(lmtPrdContVO)) {
                List<String> lmtApplySeqs = getSuccessApplySeq(lmtApplySeq);
                BigDecimal occAmt = getOccAmt(lmtApplySeqs);
                BigDecimal preOccAmt = getPreOccAmt(lmtApplySeq);
                normalTakeUpLmt(occAmt,preOccAmt,lmtPrdContVO);

            }
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private List<String> getSuccessApplySeq(String lmtApplySeq) {
		NlsApplyInfoVO nlsApplyInfoVo = new NlsApplyInfoVO();
		nlsApplyInfoVo.setLmtApplySeq(lmtApplySeq);
		nlsApplyInfoVo.setNlsApplyState(NLS_APPLY_STATE_02);
		List<NlsApplyInfoVO> nlsApplyInfoVs = Optional.ofNullable(nlsApplyInfoService.queryListByLmtApplySqe(nlsApplyInfoVo)).orElseGet(ArrayList::new);
		return nlsApplyInfoVs.stream().filter(Objects::nonNull).map(NlsApplyInfoVO::getApplySeq).collect(Collectors.toList());
	}


	private void normalTakeUpLmt(BigDecimal occAmt, BigDecimal preOccAmt, LmtPrdContVO lmtPrdContVO) throws BizException {
		lmtPrdContVO.setOccAmt(occAmt);
		lmtPrdContVO.setPreOccAmt(preOccAmt);
		lmtPrdContVO.setAvailAmt(lmtPrdContVO.getLmtAmt().subtract(occAmt).subtract(preOccAmt));
		int result = lmtPrdContService.updateByPk(lmtPrdContVO);
		if (result != 1) {
			logger.error("授信协议表 授信申请流水号【" + lmtPrdContVO.getLmtApplySeq() + "】额度占用是失败");
			throw new BizException("授信协议表 授信申请流水号【" + lmtPrdContVO.getLmtApplySeq() + "】额度占用是失败");
		}
	}

	@Override
    @RedisLock(keyParamNames = {"lmtApplySeq"})
    public void recoverLmtPro(String lmtApplySeq, String applySeq) {
		try {
			LmtPrdContVO lmtPrdContVO = new LmtPrdContVO();
			lmtPrdContVO.setLmtApplySeq(lmtApplySeq);
			lmtPrdContVO = lmtPrdContService.queryByPk(lmtPrdContVO);
			if (Objects.nonNull(lmtPrdContVO)) {
				List<String> lmtApplySeqs = getSuccessApplySeq(lmtApplySeq);
				BigDecimal occAmt = getOccAmt(lmtApplySeqs);
				normalTakeUpLmt(occAmt,BigDecimal.ZERO,lmtPrdContVO);
			}
		} catch (Exception e) {
			logger.error("更新额度占用信息 释放分布式锁失败 ");
			e.printStackTrace();
		}
	}

	@RedisLock(keyParamNames = {"lmtApplySeq"})
	public void updateLmtProdAfterRepayYed(String lmtApplySeq, String applySeq, String setlSeq) {
		try {
			LmtPrdContVO lmtPrdContVO = new LmtPrdContVO();
			lmtPrdContVO.setLmtApplySeq(lmtApplySeq);
			lmtPrdContVO = lmtPrdContService.queryByPk(lmtPrdContVO);
			if (Objects.nonNull(lmtPrdContVO)) {
				BigDecimal occAmt = getOccAmt(getSuccessApplySeq(lmtApplySeq));
				normalTakeUpLmt(occAmt, BigDecimal.ZERO, lmtPrdContVO);

				LoanRepayDetailVO loanRepayDetailVO = new LoanRepayDetailVO();
				loanRepayDetailVO.setSetlSeq(setlSeq);
				loanRepayDetailVO = loanRepayDetailService.queryByPk(loanRepayDetailVO);
				if (Objects.nonNull(loanRepayDetailVO)) {
					loanRepayDetailVO.setWfApprSts(NLS_APPLY_STATE_02);
					loanRepayDetailVO.setRpSts(RY_STS_1);
					try {
						int result = loanRepayDetailService.updateByPk(loanRepayDetailVO);
						if (result != 1) {
							logger.error("还款明细表【" + loanRepayDetailVO.getSetlSeq() + "】 同步成功后更新还款明细状态为失败");
							throw new BizException("还款明细表【" + loanRepayDetailVO.getSetlSeq() + "】同步成功后更新还款明细状态为失败");
						}
					} catch (Exception e) {
						e.printStackTrace();
						logger.error("还款明细表【" + loanRepayDetailVO.getSetlSeq() + "】同步成功后更新还款明细状态为失败");
						throw new BizException("还款明细表【" + loanRepayDetailVO.getSetlSeq() + "】同步成功后更新还款明细状态为失败");
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	@RedisLock(keyParamNames = {"lmtApplySeq"})
	public void updateLmtProYed(String lmtApplySeq, String applySeq) {
		try{
			LmtPrdContVO lmtPrdContVO = new LmtPrdContVO();
			lmtPrdContVO.setLmtApplySeq(lmtApplySeq);
			lmtPrdContVO = lmtPrdContService.queryByPk(lmtPrdContVO);
			if (Objects.nonNull(lmtPrdContVO)) {
				List<String> lmtApplySeqs = getSuccessApplySeq(lmtApplySeq);
				BigDecimal occAmt = getOccAmt(lmtApplySeqs);
				normalTakeUpLmt(occAmt,BigDecimal.ZERO,lmtPrdContVO);

			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
